#include "stdafx.h"
/** \file

\author Pablo Haramburu
Copyright:
	Copyright (C)2010 Pablo Haramburu.
License:
	This file is part of mundial2010.

	mundial2010 is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	mundial2010 is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with mundial2010.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "GoalkeeperBase.h"
#include "Movement.h"
#include "Matriz.h"
#include "Auxiliares.h"
#include <iostream>
#include <fstream>
#include <vector>
#include <cassert>
#include <cmath>
#include <complex>

#define _(x) x

int ultimasN = 10;
int limiteDeSeparacion = 25;

using namespace std;

class Goalkeeper : public GoalkeeperBase
{
public:	
	Movement computeResponse(int meassurement, double x, double y);
	/// para mediciones faltantes
	Movement computeResponse(int meassurement);
	double calcularPosicionFinal();
	double calcularPosicionConInterpolacionLineal();
	double calcularPosicionConCuadradosMinimos(int);

private:
	int n;
	vector<tPosicion> _posiciones;	
	tPosicion _posFinalPelota;
};

Movement Goalkeeper::computeResponse(int meassurement, double x, double y)
{
	Movement move = atRest;
	double pos = position();

    tPosicion p;
    p.x = x;
    p.y = y;
    p.i = meassurement;

    _posiciones.push_back(p);
	n = _posiciones.size();

	if (n > 1){
		_posFinalPelota.x = calcularPosicionFinal();
	}else{
		_posFinalPelota.x = 0;
	}

    if ( fabs((pos-_posFinalPelota.x)) <= 0.01 )
		move = atRest;
	else if ( pos > _posFinalPelota.x && pos > leftPost )
		move = toLeft;
	else if ( pos < _posFinalPelota.x && pos < rightPost )
		move = toRight;

	update(move);

	return move;
}

Movement Goalkeeper::computeResponse(int meassurement)
{
	Movement move = atRest;
	double pos = position();

    if ( (fabs(pos-_posFinalPelota.x)) <= 0.01 )
		move = atRest;
	else if ( pos > _posFinalPelota.x && pos > leftPost )
		move = toLeft;
	else if ( pos < _posFinalPelota.x && pos < rightPost )
		move = toRight;

	update(move);
	return move;
}

double Goalkeeper::calcularPosicionConInterpolacionLineal(){

	double ret = 0;    
	double x0,x1,y0,y1;

	x0 = _posiciones[n-2].x;
	y0 = _posiciones[n-2].y;
	x1 = _posiciones[n-1].x;
	y1 = _posiciones[n-1].y;

	ret = ((y1*x0)-(y0*x1))/(y1-y0);
	
	return ret;
}

double Goalkeeper::calcularPosicionConCuadradosMinimos(int cantMuestrasAUsar){
	
	if (cantMuestrasAUsar <= 1){
		return 0;
	}
	else{
	
		if (n < cantMuestrasAUsar){
			return calcularPosicionConCuadradosMinimos(cantMuestrasAUsar-1);
		}else{

			double raiz;
			vector<tPosicion> muestrasModificadasX = Transformar1(_posiciones);
			vector<tPosicion> muestrasModificadasY = Transformar2(_posiciones);
		
			tRecta rectaY = rectaCuadradosMinimos(muestrasModificadasY,cantMuestrasAUsar);
			raiz = -rectaY.b/rectaY.a;
			tRecta rectaX = rectaCuadradosMinimos(muestrasModificadasX,cantMuestrasAUsar);

			return rectaX.a * raiz + rectaX.b;
		}
	}
}

double Goalkeeper::calcularPosicionFinal(){
	
	/*if (esCorner(_posiciones)){
		tParabola p = parabola(_posiciones[0],_posiciones[1]);
		double x,y;
		x = _posiciones[n-1].x;
		y = p.a*x*x + p.b*x + p.c;
		
		if (_posiciones[n-1].y > y){
			if (_posiciones[n-1].x > _posiciones[n-2].x)
				//Ir a la derecha
				return 1;
			else
				return -1;
		}else{
			if (_posiciones[n-1].x > _posiciones[n-2].x)
				//Ir a la izquierda
				return -1;
			else
				return 1;
		}
	}else{*/
		if (n <= limiteDeSeparacion){
			return calcularPosicionConCuadradosMinimos(ultimasN);
		}else{
			return calcularPosicionConInterpolacionLineal();
		}
	//}	
}

int main(int argc, char **argv)
{
    if ( argc < 3 )
        return 1;

	std::ifstream input(argv[1]);
	if (!input) {
		std::cerr << _("No se pudo abrir el archivo de entrada!") << std::endl;
		return 2;
	}

	std::ofstream output(argv[2]);
	if (!output) {
		std::cerr << _("No se pudo crear el archivo de salida!") << std::endl;
		return 3;
	}

	//////////////////
	//std::ifstream input("test_corner3.txt");
	//std::ofstream output("salida.txt");
	//////////////////

	Goalkeeper gk;

	int meassurement; int i=1;
	while ((input >> meassurement) && meassurement != -1) {
		for(; i<meassurement; ++i)
			output << i << ' ' << gk.computeResponse(i) << std::endl;
		double x, y;
		input >> x >> y;
		assert(i==meassurement);
		output << i << ' ' << gk.computeResponse(i, x, y) << std::endl;
		++i;
	}

	return 0;
}
